#include "GRAFIKA.H"

byte far *doubleBuffer;

void setMode(byte mode){
	union REGS regs;
	regs.h.ah = 0x00;
	regs.h.al = mode;
	int86(0x10, &regs, &regs);
	if(mode == VGA_MODE){
		doubleBuffer = (byte far*)(malloc(sizeof(byte)*NUM_PIXELS));
	}
	else if(mode == TEXT_MODE){
		free(doubleBuffer);
	}
}
void fskip(FILE *fp, int num_bytes)
{
   int i;
   for (i=0; i<num_bytes; i++)
      fgetc(fp);
}
boolean loadBMP(const char *file,BITMAP *b)
{
  FILE *fp;
  long index;
  word numColors;
  int x;

  /* open the file */
  if ((fp = fopen(file,"rb")) == NULL)
  {
    printf("Error opening file %s.\n",file);
    return FALSE;
  }

  /* check to see if it is a valid bitmap file */
  if (fgetc(fp)!='B' || fgetc(fp)!='M')
  {
    fclose(fp);
    printf("%s is not a bitmap file.\n",file);
    return FALSE;
  }

  /* read in the width and height of the image, and the
     number of colors used; ignore the rest */
  fskip(fp,16);
  fread(&b->width, sizeof(word), 1, fp);
  fskip(fp,2);
  fread(&b->height,sizeof(word), 1, fp);
  fskip(fp,22);
  fread(&numColors,sizeof(word), 1, fp);
  fskip(fp,6);

  /* assume we are working with an 8-bit file */
  if (numColors==0) numColors=256;

  /* try to allocate memory */
  if ((b->data = (byte *) malloc((word)(b->width*b->height))) == NULL)
  {
    fclose(fp);
    printf("Error allocating memory for file %s.\n",file);
    return FALSE;
  }

  /* Ignore the palette information for now.
     See palette.c for code to read the palette info. */
	for(index=0;index<numColors;index++)
	  {
		b->palette[(int)(index*3+2)] = fgetc(fp) >> 2;
		b->palette[(int)(index*3+1)] = fgetc(fp) >> 2;
		b->palette[(int)(index*3+0)] = fgetc(fp) >> 2;
		x=fgetc(fp);
	  }

  /* read the bitmap */
  for(index=(b->height-1)*b->width;index>=0;index-=b->width)
    for(x=0;x<b->width;x++)
      b->data[(word)(index+x)]=(byte)fgetc(fp);

  fclose(fp);
  return TRUE;
}
void setBackground(byte color){
	memset(doubleBuffer, color, NUM_PIXELS);
}

void drawLine(int x0, int y0, int x1, int y1, byte color){
	int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
	
	dx=x1-x0;
	dy=y1-y0;
	dxabs=abs(dx);
	dyabs=abs(dy);
	sdx=sgn(dx);
	sdy=sgn(dy);
	x=dyabs>>1;
	y=dxabs>>1;
	px=x0;
	py=y0;

	doubleBuffer[(py<<8)+(py<<6)+px] = color;

	if (dxabs>=dyabs)
	{
		for(i=0;i<dxabs;i++)
		{
			y+=dyabs;
			if(y>=dxabs)
			{
				y-=dxabs;
				py+=sdy;
			}
			px+=sdx;
			doubleBuffer[(py<<8)+(py<<6)+px] = color;
		}
	}
	else
	{
		for(i=0;i<dyabs;i++)
		{
			x+=dxabs;
			if(x>=dyabs)
			{
				x-=dyabs;
				px+=sdx;
			}
			py+=sdy;
			doubleBuffer[(py<<8)+(py<<6)+px] = color;
		}
	}
}

void drawRectangle(int left, int top, int right, int bottom, byte color){
	word topOffset, bottomOffset, i;
	topOffset = (top<<8)+(top<<6);
	bottomOffset = (bottom<<8)+(bottom<<6);
	memset(&doubleBuffer[topOffset+left], color, right-left+1);
	memset(&doubleBuffer[bottomOffset+left], color, right-left+1);
	for(i=topOffset;i<bottomOffset;i+=SCREEN_WIDTH)
	{
		doubleBuffer[i+left] = color;
		doubleBuffer[i+right] = color;
	}
}

void fillRectangle(int left, int top, int right, int bottom, byte color){
	word topOffset, bottomOffset, width, i;
	
	topOffset = (top<<8)+(top<<6)+left;
	bottomOffset = (bottom<<8)+(bottom<<6)+left;
	width = right-left+1;
	for(i=topOffset;i<=bottomOffset;i+=SCREEN_WIDTH)
	{
		memset(&doubleBuffer[i], color, width);
	}
}

void redraw(void){
	while ((inp(INPUT_STATUS_1) & VRETRACE));
	while (!(inp(INPUT_STATUS_1) & VRETRACE));
	memcpy((byte far*)0xA0000000L,doubleBuffer,NUM_PIXELS);
}

void drawCircle(int x, int y, int radius, byte color){	
	int e, ddx = 1, ddy, delta1, delta2 = 0;
	word delta1Offset, delta2Offset, center = (y<<8)+(y<<6)+x;
	radius--;
	e = 1 - radius;
	ddy = -(radius<<1);
	delta1= radius;
	delta1Offset = (delta1<<8)+(delta1<<6);
	
	doubleBuffer[center+delta1] = color;
	doubleBuffer[center-delta1Offset] = color;
	doubleBuffer[center-delta1] = color;
	doubleBuffer[center+delta1Offset] = color;
	
	while(delta2 < delta1)
	{
		if(e >= 0)
		{
			delta1--;
			ddy += 2;
			e += ddy;
		}
		delta2++;
		ddx += 2;
		e += ddx;	
		
		delta1Offset = (delta1<<8)+(delta1<<6);
		delta2Offset = (delta2<<8)+(delta2<<6);
		doubleBuffer[center+delta1-delta2Offset] = color;
		doubleBuffer[center+delta2-delta1Offset] = color;
		doubleBuffer[center-delta2-delta1Offset] = color;
		doubleBuffer[center-delta1-delta2Offset] = color;
		doubleBuffer[center-delta1+delta2Offset] = color;
		doubleBuffer[center-delta2+delta1Offset] = color;
		doubleBuffer[center+delta2+delta1Offset] = color;
		doubleBuffer[center+delta1+delta2Offset] = color;		
	}		
}

void fillCircle(int x, int y, int radius, byte color){	
	int e, ddx = 1, ddy, delta1, delta2 = 0,i;
	word delta1Offset, delta2Offset, center = (y<<8)+(y<<6)+x;
	radius--;
	e = 1 - radius;
	ddy = -(radius<<1);
	delta1= radius;	
	
	while(delta2 < delta1)
	{		
		delta1Offset = (delta1<<8)+(delta1<<6);
		delta2Offset = (delta2<<8)+(delta2<<6);
		for(i=delta1;i>=delta2;i--,delta1Offset-=SCREEN_WIDTH)
		{
			doubleBuffer[center+i-delta2Offset] = color;
			doubleBuffer[center+delta2-delta1Offset] = color;
			doubleBuffer[center-delta2-delta1Offset] = color;
			doubleBuffer[center-i-delta2Offset] = color;
			doubleBuffer[center-i+delta2Offset] = color;
			doubleBuffer[center-delta2+delta1Offset] = color;
			doubleBuffer[center+delta2+delta1Offset] = color;
			doubleBuffer[center+i+delta2Offset] = color;
		}				
		
		if(e >= 0)
		{
			delta1--;
			ddy += 2;
			e += ddy;
		}
		delta2++;
		ddx += 2;
		e += ddx;
	}		
}
void putPixel(int x, int y, byte color){
	doubleBuffer[(y<<8)+(y<<6)+x] = color;
}
byte getPixel(int x, int y){
	return doubleBuffer[(y<<8)+(y<<6)+x];
}
void drawBitmap(BITMAP *bmp,int x,int y)
{
  int j;
  word screenOffset = (y<<8)+(y<<6)+x;
  word bitmapOffset = 0;

  for(j=0;j<bmp->height;j++)
  {
    memcpy(&doubleBuffer[screenOffset],&bmp->data[bitmapOffset],bmp->width);

    bitmapOffset+=bmp->width;
    screenOffset+=SCREEN_WIDTH;
  }
}
void drawTransparentBitmap(BITMAP *bmp,int x,int y, byte background)
{
  int j,i;
  byte data;
  word screenOffset = (y<<8)+(y<<6)+x;
  word bitmapOffset = 0;

  for(j=0;j<bmp->height;j++)
  {
    for(i=0;i<bmp->width;i++,bitmapOffset++)
    {
      data = bmp->data[bitmapOffset];
      if (data != background) doubleBuffer[screenOffset+x+i] = data;
    }
    screenOffset+=SCREEN_WIDTH;
  }
}
void drawButton(BUTTON *button, byte transparent)
{
  int x, y;
  word screenOffset = (button->y<<8)+(button->y<<6);
  word bitmapOffset = 0;
  byte data;
  int base = ((button->state)%(button->numState))*(button->width*button->height);
  int posX = button->x;
  for(y=0;y<button->height;y++)
  {
    for(x=0;x<button->width;x++,bitmapOffset++)
    {
      data = button->bitmap[base+bitmapOffset];
      if (data != transparent) doubleBuffer[screenOffset+posX+x] = data;
    }
    screenOffset+=SCREEN_WIDTH;
  }
}
void setPalette(byte *palette)
{
  int i;
  outp(PALETTE_INDEX,0);              /* tell the VGA that palette data
                                         is coming. */
  for(i=0;i<256*3;i++)
    outp(PALETTE_DATA,palette[i]);    /* write the data */
}
